using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace GameStateManagement
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class StaticEnemy : OrbitingActor
    {
        Player player;
        Vector3 fire_vector;
        float missile_speed = 2500;
        public List<Missile> missiles;
        public static float MissileCooldownTime = 2000.0f;
        int m_LastMissileFireTime = -(int)MissileCooldownTime;

        float m_fMagnitudeRatio;
        Planet planet;
        float radius;

        public StaticEnemy(Game game, Player temp, float magnitudeRatio, float speed, List<Missile> missile_list, Planet planet_)
            : base(game)
        {
            sMeshName = "Asteroid";
            player = temp;
            fire_vector = Vector3.Zero;
            bPhysicsDriven = true;
            missiles = missile_list;

            m_fMagnitudeRatio = magnitudeRatio;
            m_fSpeed = speed;
            planet = planet_;
            radius = planet.ModelBounds.Radius * planet.m_fScale;
            // TODO: Construct any child components here
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here
            WormholeManager.GetWormholeManager().AddToScope(this);
            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            if (!GameplayScreen.pause && !GameplayScreen.gameOver)
            {
                Vector3 ship_position = new Vector3(player.m_Ship.m_vWorldPosition.X, player.m_Ship.m_vWorldPosition.Y, player.m_Ship.m_vWorldPosition.Z);
                Vector3 ship_velocity = new Vector3(player.m_Ship.m_vVelocity.X, player.m_Ship.m_vVelocity.Y, player.m_Ship.m_vVelocity.Z);

                float time_one, time_two;

                //use quadratic formula
                float a = (float)Math.Pow(ship_velocity.X, 2) + (float)Math.Pow(ship_velocity.Y, 2) + (float)Math.Pow(ship_velocity.Z, 2) - (float)Math.Pow(missile_speed, 2);
                float b = 2 * ship_position.X * ship_velocity.X - 2 * m_vWorldPosition.X * ship_velocity.X;
                b += 2 * ship_position.Y * ship_velocity.Y - 2 * m_vWorldPosition.Y * ship_velocity.Y;
                b += 2 * ship_position.Z * ship_velocity.Z - 2 * m_vWorldPosition.Z * ship_velocity.Z;
                float c = (float)Math.Pow(m_vWorldPosition.X, 2) + (float)Math.Pow(m_vWorldPosition.Y, 2) + (float)Math.Pow(m_vWorldPosition.Z, 2);
                c -= (2 * ship_position.X * m_vWorldPosition.X + 2 * ship_position.Y * m_vWorldPosition.Y + 2 * ship_position.Z * m_vWorldPosition.Z);
                c -= (m_vWorldPosition.X + m_vWorldPosition.Y + m_vWorldPosition.Z);

                time_one = (-b - (float)Math.Sqrt(b * b - 4 * a * c)) / (2 * a);
                time_two = (-b + (float)Math.Sqrt(b * b - 4 * a * c)) / (2 * a);

                //no positive solution. don't fire
                if (time_one != float.NaN && time_two != float.NaN)
                {
                    if (time_one <= 0 && time_two <= 0)
                    {
                        fire_vector = Vector3.Zero;
                    }
                    else if (time_one <= 0)
                    {
                        //fire using time two since it is a positive real solution
                        if ((b * b - 4 * a * c) < 0)
                        {
                            fire_vector = ship_position - m_vWorldPosition;
                        }
                        else
                        {
                            fire_vector = ship_position + Vector3.Multiply(ship_velocity, time_two) - m_vWorldPosition;
                        }
                        if (fire_vector.X != 0 || fire_vector.Y != 0 || fire_vector.Z != 0)
                        {
                            fire_vector.Normalize();
                            //Console.WriteLine(fire_vector.ToString());
                            FireMissile();
                        }
                    }
                    else
                    {
                        //use time one since its the better positive real solution
                        if ((b * b - 4 * a * c) < 0)
                        {
                            fire_vector = ship_position - m_vWorldPosition;
                        }
                        else
                        {
                            fire_vector = ship_position + Vector3.Multiply(ship_velocity, time_one) - m_vWorldPosition;
                        }
                        if (fire_vector.X != 0 || fire_vector.Y != 0 || fire_vector.Z != 0)
                        {
                            fire_vector.Normalize();
                            //Console.WriteLine(fire_vector.ToString());
                            FireMissile();
                        }
                    }
                }

                ScaleRadiusBetweenSphereAndPlanet(m_fMagnitudeRatio);

                Vector3 forward = new Vector3();
                forward = m_vWorldPosition - player.m_Ship.m_vWorldPosition;
                Vector3 up = new Vector3();
                up.X = forward.X + 1;
                up.Y = forward.Y;
                up.Z = forward.Z;

                up = Vector3.Cross(up, forward);
                up.Normalize();

                Vector3 left = Vector3.Cross(up, forward);
                left.Normalize();

                WorldTransform.Forward = forward;
                WorldTransform.Left = left;
                WorldTransform.Up = up;

                Quaternion temp_quat;
                Vector3 temp_scale;
                Vector3 temp_translate;

                WorldTransform.Decompose(out temp_scale, out temp_quat, out temp_translate);

                m_qRotation = temp_quat;
                m_vWorldPosition = temp_translate;
                m_fScale = temp_scale.X;

                base.Update(gameTime);
            }
        }

        public void FireMissile()
        {
            if (System.Environment.TickCount - m_LastMissileFireTime >= MissileCooldownTime && check_fire() == true)
            {
                // Create missile
                Missile missile = new Missile(Game);
                missile.Enemy_Missile = true;
                missile.Speed = missile_speed;
                Game.Components.Add(missile);
                missiles.Add(missile);

                // Position the missile, angle, and velocity.
                missile.m_vWorldPosition = m_vWorldPosition;
                missile.m_qRotation = m_qRotation;
                missile.moving_vector = fire_vector;
                m_LastMissileFireTime = System.Environment.TickCount;

                //Console.WriteLine(get_fire_vector());
                // Play sound
            }
        }

        public string get_fire_vector()
        {
            return fire_vector.ToString();
        }

        //for first case find vector from enemy to center of planet. the find vector to edge of planet. 
        //or take the radius of the planet and use pythagorean theorem to find distance from you to maximumum edge of planet. 
        //if the distance between enemy and the player is less than this value, than its ok to fire
        //if not, then go to hard case

        //to find angle between to_planet
        private bool check_fire()
        {
            float angle_player;
            float angle_edge_planet;
            float to_edge_planet_distance = (planet.m_vWorldPosition - m_vWorldPosition).LengthSquared();
            to_edge_planet_distance += radius * radius;

            if ((player.m_Ship.m_vWorldPosition - m_vWorldPosition).LengthSquared() < to_edge_planet_distance)
                return true;
            else
            {
                Vector3 to_planet = new Vector3();
                to_planet = planet.m_vWorldPosition - m_vWorldPosition;
                angle_player = (float)Math.Acos(Vector3.Dot(fire_vector, to_planet)/(to_planet.Length() * fire_vector.Length()));

                angle_edge_planet = (float)Math.Acos((planet.m_vWorldPosition - m_vWorldPosition).Length() / (Math.Sqrt(to_edge_planet_distance)));

                if (angle_player > angle_edge_planet)
                    return true;
                else
                    return false;
            }
        }
    }
}
